package com.uinnova.product.eam.init.iam;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.google.common.collect.Sets;
import com.uinnova.product.eam.comm.bean.DeptInfoIam;
import com.uinnova.product.eam.comm.bean.EmpDeptRelaIam;
import com.uinnova.product.eam.comm.bean.EmpInfoIam;
import com.uinnova.product.eam.comm.model.CDeptInfoIam;
import com.uinnova.product.eam.comm.model.CEmpDeptRelaIam;
import com.uinnova.product.eam.comm.model.CEmpInfoIam;
import com.uinnova.product.eam.db.DeptInfoIamDao;
import com.uinnova.product.eam.db.EmpDeptRelaIamDao;
import com.uinnova.product.eam.db.EmpInfoIamDao;
import com.uinnova.product.vmdb.comm.util.CommUtil;
import com.uino.api.client.permission.IRoleApiSvc;
import com.uino.api.client.permission.IUserApiSvc;
import com.uino.bean.cmdb.business.ImportSheetMessage;
import com.uino.bean.permission.base.*;
import com.uino.bean.permission.business.UserInfo;
import com.uino.dao.permission.ESOrgSvc;
import com.uino.dao.permission.ESRoleSvc;
import com.uino.dao.permission.ESUserSvc;
import com.uino.dao.permission.rlt.ESPerssionCommSvc;
import com.uino.dao.util.ESUtil;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @description: 国投IAM数据同步
 * @author: LiMG
 * @create: 2024-06-05 11:17:08
 **/
@Slf4j
@Service
public class SyncIAMUserSvc {

    @Autowired
    ESRoleSvc roleSvc;

    @Autowired
    ESPerssionCommSvc commSvc;

    @Autowired
    private ESOrgSvc orgBuinessSvc;

    @Autowired
    private ESOrgSvc orgSvc;

    @Autowired
    private ESUserSvc userSvc;

    @Autowired
    private IRoleApiSvc roleApiSvc;

    @Autowired
    private IUserApiSvc userApiSvc;

    @Autowired
    private DeptInfoIamDao deptInfoIamDao;

    @Autowired
    private EmpInfoIamDao empInfoIamDao;

    @Autowired
    private EmpDeptRelaIamDao empDeptRelaIamDao;

    @Value("${http.resource.space}")
    private String httpPath;

    private static final String VIEW_NAME = "视图配置中国投IAM用户数据同步配置";

    /**
     * 默认邮箱
     */
    private static String DEFAULT_EMAIL;

    /**
     * 默认角色
     */
    private static String DEFAULT_ROLE;

    /**
     * 管理员权限的用户集合
     */
    private static List<String> ADMIN_USER_LIST;

    @Transactional(rollbackFor = Exception.class)
    public void syncUserData(JSONObject jsonConfig) {
        // 校验配置项
        checkConfig(jsonConfig);
        // 同步部门数据
        syncDepartmentData();
        // 同步用户数据
        syncUserData();
        // 删除多余部门
        delDepartmentData();
    }

    /**
     * 校验配置项
     *
     * @param jsonConfig
     */
    private void checkConfig(JSONObject jsonConfig) {
        DEFAULT_EMAIL = jsonConfig.getString("defaultEmail");
        DEFAULT_ROLE = jsonConfig.getString("defaultRole");
        JSONArray jsonArray = jsonConfig.getJSONArray("adminUsers");
        if (null != jsonArray) {
            ADMIN_USER_LIST = jsonArray.toJavaList(String.class);
        }

        Assert.isTrue(StrUtil.isNotEmpty(DEFAULT_EMAIL), VIEW_NAME + "未找到【defaultEmail】相关配置");
        Assert.isTrue(StrUtil.isNotEmpty(DEFAULT_ROLE), VIEW_NAME + "未找到【defaultRole】相关配置");
    }

    /**
     * 获取EA库中部门数据
     *
     * @return
     */
    private List<SysOrg> getEaOrgList() {
        // 获取EA库中部门数据
        List<SysOrg> resultList = new ArrayList<>();
        BoolQueryBuilder query = QueryBuilders.boolQuery()
                .must(QueryBuilders.existsQuery("remark.keyword"));
        long count = orgSvc.countByCondition(query);
        int pageCount = (int) (count / 3000 + 1);
        for (int i = 1; i <= pageCount; i++) {
            Page<SysOrg> list = orgSvc.getListByQuery(i, 3000, query);
            resultList.addAll(list.getData());
        }
        return resultList;
    }

    /**
     * 获取EA库中用户数据
     *
     * @return
     */
    private List<SysUser> getEaUserList() {
        // 获取EA库中部门数据
        List<SysUser> resultList = new ArrayList<>();
        BoolQueryBuilder query = QueryBuilders.boolQuery()
                .must(QueryBuilders.existsQuery("iamUserId.keyword"));
        long count = userSvc.countByCondition(query);
        int pageCount = (int) (count / 3000 + 1);
        for (int i = 1; i <= pageCount; i++) {
            Page<SysUser> list = userSvc.getListByQuery(i, 3000, query);
            resultList.addAll(list.getData());
        }
        return resultList;
    }

    /**
     * 获取EA库中用户数据
     *
     * @return
     */
    private List<SysUser> getEaUserListByIamUserList(List<EmpInfoIam> userList) {

        Set<String> userLoginCodes = userList.stream().map(EmpInfoIam::getEmp_oa).collect(Collectors.toSet());
        BoolQueryBuilder userQuery = QueryBuilders.boolQuery();
        userQuery.must(QueryBuilders.termsQuery("loginCode.keyword", userLoginCodes));
        List<SysUser> resultList = userSvc.getListByQueryScroll(userQuery);
        return resultList;
    }

    /**
     * 获取角色数据并填充
     * @param users
     * @return
     */
    private List<UserInfo> fillRoleInfo(List<SysUser> users) {
        List<UserInfo> infos = new ArrayList<UserInfo>();
        Map<Long, String> orgIdAllNameMap = null;
        if (!BinaryUtils.isEmpty(users)) {
            infos = CommUtil.copy(users, UserInfo.class);
            Set<Long> userIds = infos.stream().map(SysUser::getId).collect(Collectors.toSet());

            // 查询用户-角色关系
            Map<Long, List<SysUserRoleRlt>> urMap = new HashMap<>();
            Map<Long, SysRole> rMap = new HashMap<>();
            List<SysUserRoleRlt> uRoleRlts = new ArrayList<>();

            List<Set<Long>> splitUserIds = this.splitSet(userIds,9000);

            for(Set<Long> userid : splitUserIds){
                uRoleRlts.addAll(commSvc.getUserRoleRltByUserIds(userid));
            }


            if (!BinaryUtils.isEmpty(uRoleRlts)) {
                urMap = BinaryUtils.toObjectGroupMap(uRoleRlts, "userId");
                Set<Long> roleIds = uRoleRlts.stream().map(SysUserRoleRlt::getRoleId).collect(Collectors.toSet());
                List<SysRole> roles = roleSvc
                        .getListByQuery(QueryBuilders.boolQuery().must(QueryBuilders.termsQuery("id", roleIds)));
                rMap = BinaryUtils.toObjectMap(roles, "id");
            }

            // 组装用户信息
            for (UserInfo info : infos) {
                // 拼装角色数据
                List<SysUserRoleRlt> urRlts = urMap.get(info.getId());
                if (!BinaryUtils.isEmpty(urRlts)) {
                    Set<SysRole> roles = new HashSet<SysRole>();
                    for (SysUserRoleRlt mr : urRlts) {
                        SysRole role = rMap.get(mr.getRoleId());
                        if (role != null) {
                            roles.add(role);
                        }
                    }
                    info.setRoles(roles);
                }
            }
        }
        return infos;
    }

    private static <T> List<Set<T>> splitSet(Set<T> set, int subsetSize) {
        List<Set<T>> subsets = new ArrayList<>();
        Iterator<T> iterator = set.iterator();

        while (iterator.hasNext()) {
            Set<T> subset = new HashSet<>();
            int count = 0;

            while (iterator.hasNext() && count < subsetSize) {
                subset.add(iterator.next());
                count++;
            }

            subsets.add(subset);
        }

        return subsets;
    }

    /**
     * 同步部门数据
     */
    private void syncDepartmentData() {
        log.info("开始同步IAM部门数据");
        CDeptInfoIam deptInfoIam = new CDeptInfoIam();
        List<DeptInfoIam> list = deptInfoIamDao.selectList(deptInfoIam, null);
        if (list.isEmpty()) {
            log.info("dept_info_iam表数据为空，不做同步处理");
            return;
        }
        List<SysOrg> eaOrgList = getEaOrgList();
        Map<String, Long> orgIdMap = eaOrgList.stream().collect(Collectors.toMap(item -> item.getRemark().split("-")[0], item -> Long.parseLong(item.getRemark().split("-")[1])));
        // 初始化所有组织的ID
        for (DeptInfoIam infoIam : list) {
            if (null == orgIdMap.get(infoIam.getDept_id())) {
                orgIdMap.put(infoIam.getDept_id(), ESUtil.getUUID());
            }
        }
        List<SysOrg> orgList = new ArrayList<>();
        for (DeptInfoIam infoIam : list) {
            SysOrg org = new SysOrg();
            String deptId = infoIam.getDept_id();
            org.setId(orgIdMap.get(deptId));
            org.setOrgName(infoIam.getDept_name());
            org.setOrderNo(infoIam.getDept_int_id());
            String parentId = infoIam.getSupr_dept_id();
            org.setParentOrgId(null == parentId || !orgIdMap.containsKey(parentId) ? 1L : orgIdMap.get(parentId));
            org.setCreator("IAM_SYNC");
            org.setRemark(deptId + "-" + org.getId());
            orgList.add(org);
        }
        Integer i = orgSvc.saveOrUpdateBatch(orgList);
        if (i > 0) {
            log.info("IAM部门数据同步成功");
        }
    }


    /**
     * 删除多余部门
     */
    private void delDepartmentData() {
        log.info("开始删除差异IAM部门数据");
        CDeptInfoIam deptInfoIam = new CDeptInfoIam();
        List<DeptInfoIam> list = deptInfoIamDao.selectList(deptInfoIam, null);
        if (list.isEmpty()) {
            log.info("dept_info_iam表数据为空，不做同步处理");
            return;
        }
        List<SysOrg> eaOrgList = getEaOrgList();
        Map<String, Long> orgIdMap = eaOrgList.stream().collect(Collectors.toMap(item -> item.getRemark().split("-")[0], item -> Long.parseLong(item.getRemark().split("-")[1])));

        Set<String> delKey = orgIdMap.keySet();
        // 初始化所有组织的ID
        for (DeptInfoIam infoIam : list) {
            if (orgIdMap.containsKey(infoIam.getDept_id())) {
                delKey.remove(infoIam.getDept_id());
            }
        }

        Set<Long> delRes = delKey.stream().map(x->orgIdMap.get(x)).collect(Collectors.toSet());

        if(delRes.size() == 0){
            log.info("IAM部门同步--无多余部门");
            return;
        }
        Integer i = orgSvc.deleteByIds(delRes);
        if (i > 0) {
            log.info("IAM部门删除多余部门成功");
        }
    }

    /**
     * 同步用户数据
     */
    private void syncUserData() {
        log.info("开始同步IAM用户数据");
        CEmpInfoIam empInfoIam = new CEmpInfoIam();
        List<EmpInfoIam> userList = empInfoIamDao.selectList(empInfoIam, null);
        CEmpDeptRelaIam empDeptRealIam = new CEmpDeptRelaIam();
        List<EmpDeptRelaIam> empDeptList = empDeptRelaIamDao.selectList(empDeptRealIam, null);
        if (userList.isEmpty()) {
            log.info("emp_info_iam表数据为空，不做同步处理");
            return;
        }
        if (empDeptList.isEmpty()) {
            log.info("EMP_DEPT_RELA_IAM表数据为空，不做同步处理");
        }
        Map<String, List<EmpDeptRelaIam>> empDeptsMap = empDeptList.stream().collect(Collectors.groupingBy(item -> item.getEmp_id()));
        // 获取EA库中部门数据
        List<SysOrg> eaOrgList = getEaOrgList();
        Map<String, SysOrg> orgMap = eaOrgList.stream().collect(Collectors.toMap(item -> item.getRemark().split("-")[0], item -> item));
        Map<String, Long> orgIdMap = eaOrgList.stream().collect(Collectors.toMap(item -> item.getRemark().split("-")[0], item -> Long.parseLong(item.getRemark().split("-")[1])));

        /**
         * 获取EA中组织的全路径组织名称
         */
        Set<Long> orgIds = eaOrgList.stream().map(item->item.getId()).collect(Collectors.toSet());
        Map<Long, String>   orgIdAllNameMap = orgBuinessSvc.getOrgIdAllNameMap(1L, orgIds);

        List<Long> valuesToMatch = orgIdMap.values().stream().collect(Collectors.toList());
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        boolQuery.must(QueryBuilders.termsQuery("id", valuesToMatch));
        HashSet<String> roleNames = Sets.newHashSet();
        roleNames.add("员工");
        BoolQueryBuilder must = QueryBuilders.boolQuery().must(QueryBuilders.termsQuery("roleName.keyword", roleNames));
        List<SysRole> defaultRoles = roleApiSvc.getRolesByQuery(must);
        HashSet<String> adminRole = Sets.newHashSet();
        adminRole.add("admin");
        BoolQueryBuilder builder = QueryBuilders.boolQuery().must(QueryBuilders.termsQuery("roleName.keyword", adminRole));
        List<SysRole> adminRoles = roleApiSvc.getRolesByQuery(builder);
        List<SysUser> eaUserList = getEaUserListByIamUserList(userList);

        Map<String,String> exitId = new HashMap<>();
        eaUserList.stream().filter(item -> StrUtil.isNotEmpty(item.getIamUserId())).forEach(item->{
            String id = item.getIamUserId().split("-")[0];
            if(exitId.containsKey(id)){
                log.error("出现重复iam id ，{}",item.getUserName(),exitId.get(id));
            }
            exitId.put(id,item.getUserName());
        });

        Map<String, Long> userIdMap = eaUserList.stream().filter(item -> StrUtil.isNotEmpty(item.getIamUserId())).collect(Collectors.toMap(item -> item.getIamUserId().split("-")[0], item -> Long.parseLong(item.getIamUserId().split("-")[1])));

        List<UserInfo> orginUsers  = this.fillRoleInfo(eaUserList);
        Map<String, Set<SysRole>> RoleMap = orginUsers.stream().filter(item -> StrUtil.isNotEmpty(item.getIamUserId()) && item.getRoles() != null).collect(Collectors.toMap(item -> item.getIamUserId().split("-")[0], item -> item.getRoles()));

        Map<String, String> loginCodeMap = eaUserList.stream().filter(item -> StrUtil.isNotEmpty(item.getIamUserId())).collect(Collectors.toMap(item -> item.getIamUserId().split("-")[0], item -> item.getLoginCode()));
        if (defaultRoles.isEmpty()) {
            SysRole sysRole = new SysRole();
            sysRole.setRoleName("员工");
            sysRole.setCreator("admin");
            sysRole.setRoleDesc("内部员工");
            Long[] roleIds = {1L, 2L, 3L, 4L, 5L};
            sysRole.setBootEntryRoleIds(Arrays.stream(roleIds).collect(Collectors.toList()));
            roleApiSvc.saveOrUpdate(sysRole);
            defaultRoles = roleApiSvc.getRolesByQuery(must);
        }
        List<UserInfo> saveUserList = new ArrayList<>();
        for (EmpInfoIam user : userList) {
            UserInfo userInfo = new UserInfo();
            String userId = user.getEmp_id();
            if (userIdMap.containsKey(userId)) {
                userInfo.setId(userIdMap.get(userId));
            } else {
                long uuid = ESUtil.getUUID();
                userInfo.setId(uuid);
                userIdMap.put(userId, uuid);
            }
            userInfo.setUserName(user.getEmp_name());
            userInfo.setLoginCode(user.getEmp_oa());
            userInfo.setMobileNo("");
            userInfo.setEmailAdress(StrUtil.isNotEmpty(user.getEmail()) ? user.getEmail() : DEFAULT_EMAIL);
            userInfo.setStatus(1);
            userInfo.setDomainId(1L);
            userInfo.setSuperUserFlag(0);
            userInfo.setLockFlag(0);
            userInfo.setTryTimes(0);
            userInfo.setStatName(user.getEmp_stat_name());
            userInfo.setStatCD(user.getEmp_stat_cd());

            Set<SysOrg> orgSet = new HashSet<>();
            List<EmpDeptRelaIam> orgList = empDeptsMap.get(user.getEmp_id());
            if(orgList == null){
                orgList = new ArrayList<>();
            }
            for (EmpDeptRelaIam dept : orgList) {
                if(orgMap.containsKey(dept.getDept_id())){
                    orgSet.add(orgMap.get(dept.getDept_id()));
                    if(dept.getIs_main_dept_cd().equals("1")){
                        userInfo.setMainOrgId(orgMap.get(dept.getDept_id()).getId());
                        userInfo.setMainOrgAllLevelName(orgIdAllNameMap.get(orgMap.get(dept.getDept_id()).getId()));
                    }
                }
            }
            /**
             * 如果所属组织不存在，跳过该用户
             */
            if(orgSet.isEmpty() && !userIdMap.containsKey(userId)) continue;


            userInfo.setOrgs(orgSet);
            userInfo.setRoles(new HashSet<>(defaultRoles));
            if (null != ADMIN_USER_LIST && ADMIN_USER_LIST.contains(user.getEmp_oa())) {
                userInfo.setRoles(new HashSet<>(adminRoles));
            }
            /**
             * 获取该用户在ea中的角色，并赋予
             */
            Set<SysRole> currentRole =  new HashSet<>(userInfo.getRoles());
            if(RoleMap.containsKey(userId)) {
                currentRole.addAll(RoleMap.get(userId));
            }
            userInfo.setRoles(currentRole);

            userInfo.setIamUserId(userId + "-" + userInfo.getId());
            userInfo.setIcon("/122/defaultIcon/default_account_photo.png");
            saveUserList.add(userInfo);
        }
        int batchSize = 3000;
        // 创建原始列表的副本
        List<UserInfo> originalSaveUserList = new ArrayList<>(saveUserList);
        int totalSize = originalSaveUserList.size();
        // 使用 double 类型避免整数除法问题
        int batchCount = (int) Math.ceil((double) totalSize / batchSize);

        log.info("saveUserList总条数:{}", totalSize);

        for (int i = 0; i < batchCount; i++) {
            log.info("开始同步第{}批次数据", i);
            int start = i * batchSize;
            int end = Math.min(start + batchSize, totalSize);
            log.info("开始索引:{}, 结束索引:{}", start, end);
            List<UserInfo> list = originalSaveUserList.subList(start, end);
            // 使用列表副本，防止list被篡改
            ImportSheetMessage importSheetMessage = userApiSvc.syncUserBatch(new ArrayList<>(list));
            log.info("第{}批次员工同步情况：-{}", i, importSheetMessage.toString());
        }
        // 计算此次同步的用户差异数据
//        Map<String, Long> syncMap = userList.stream().collect(Collectors.toMap(item -> item.getEmp_id(), item -> 1L));
        // 删除IAM已删除或离职的用户
//        deleteDifferentUser(syncMap, loginCodeMap);
    }

    /**
     * 删除IAM已删除或离职的用户
     */
    private void deleteDifferentUser(Map<String, Long> syncMap, Map<String, String> loginCodeMap) {
        Set<String> existUserMap = new HashSet<>(loginCodeMap.keySet());
        // 计算此次同步的用户差异数据，删除EA库中存在但IAM中不存在的用户
        existUserMap.removeAll(syncMap.keySet());
        if (!existUserMap.isEmpty()) {
            log.info("开始删除EA系统中IAM中不存在的用户:{}", existUserMap);
            List<String> loginCodes = new ArrayList<>(existUserMap);
            userApiSvc.deleteSysUserByLoginCodeBatch(loginCodes);
            log.info("EA系统中IAM中不存在的用户删除成功");
        }
        log.info("IAM用户数据同步完成");
    }

}
